package ro.ubbcluj.cs.damate.managers.management;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import ro.ubbcluj.cs.damate.managers.BaseView;
import ro.ubbcluj.cs.damate.managers.administration.AdministrationView;
import ro.ubbcluj.cs.damate.managers.administration.UserMapper;
import ro.ubbcluj.cs.damate.persistence.entities.Group;
import ro.ubbcluj.cs.damate.persistence.entities.Section;
import ro.ubbcluj.cs.damate.persistence.entities.User;
import ro.ubbcluj.cs.damate.services.GroupService;
import ro.ubbcluj.cs.damate.services.SectionService;
import ro.ubbcluj.cs.damate.services.UserService;
import ro.ubbcluj.cs.damate.webutils.JSFUtil;
import ro.ubbcluj.cs.damate.webutils.MessageProvider;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @author Lorand Fazakas
 */
@Component
@Scope("view")
public class SectionManager extends BaseView implements Serializable {

    @Autowired
    private ManagerView managerView;

    @Autowired
    private GroupService groupService;

    @Autowired
    private UserService userService;

    @Autowired
    private SectionService sectionService;

    private Section newOrModifiedSectionBean;
    private List<User> selectedManagers;
    private List<UserMapper> assignedSectionManagers;
    private List<User> assignableSectionManagers;
    private Group filteredGroup;

    private List<Section> sections;
    private List<Section> filteredSections;

    private UIComponent assignedManagersUIComponent;

    public void save() {
        if (!hasAssignedManager()) {
            JSFUtil.addMessage(assignedManagersUIComponent.getClientId(), FacesMessage.SEVERITY_ERROR, MessageProvider.getValue("managerPage.sectionManagement.managerAssignment.notAssigned"));
        } else if (!hasLeaderManager()) {
            JSFUtil.addMessage(assignedManagersUIComponent.getClientId(), FacesMessage.SEVERITY_ERROR, MessageProvider.getValue("managerPage.sectionManagement.managerAssignment.noLeaderSelected"));
        } else {
            newOrModifiedSectionBean.setSectionManagers(new ArrayList<User>());
            for(UserMapper manager : assignedSectionManagers) {
                newOrModifiedSectionBean.getSectionManagers().add(manager.getUser());
                if (manager.isChecked()) {
                    newOrModifiedSectionBean.setSectionLeader(manager.getUser());
                }
            }
            sectionService.create(newOrModifiedSectionBean);
            clean();
            managerView.switchPanel(ManagerView.ManagerPanel.LIST_SECTIONS.name());
        }
    }

    public void edit(Section section) {
        this.newOrModifiedSectionBean = section;
        this.assignedSectionManagers = new ArrayList<UserMapper>();
        for(User manager : newOrModifiedSectionBean.getSectionManagers()) {
            assignedSectionManagers.add(new UserMapper(manager, manager.getUsername().equals(newOrModifiedSectionBean.getSectionLeader().getUsername())));
        }
        managerView.switchPanel(ManagerView.ManagerPanel.NEW_SECTION.name());
    }

    public void delete(Section section) {
        sectionService.delete(section);
        clean();
    }

    public void openPanel(String panelName) {
        clean();
        managerView.switchPanel(panelName);
    }

    private void clean() {
        this.newOrModifiedSectionBean = null;
        this.selectedManagers = null;
        this.assignedSectionManagers = null;
        this.assignableSectionManagers = null;
        this.filteredGroup = null;
        this.sections = null;
        this.filteredSections = null;
    }

    private boolean hasAssignedManager() {
        return assignedSectionManagers != null && !assignedSectionManagers.isEmpty();
    }

    private boolean hasLeaderManager() {
        if (hasAssignedManager()) {
            for(UserMapper manager : assignedSectionManagers) {
                if (manager.isChecked()) {
                    return true;
                }
            }
        }
        return false;
    }

    public void removeAssignedManager(UserMapper manager) {
        assignedSectionManagers.remove(manager);
    }

    public void removeAllAssignedManager() {
        if (assignedSectionManagers != null) {
            assignedSectionManagers.clear();
        }
    }

    public Section getNewOrModifiedSectionBean() {
        if (newOrModifiedSectionBean == null) {
            this.newOrModifiedSectionBean = new Section();
        }
        return newOrModifiedSectionBean;
    }

    public void setNewOrModifiedSectionBean(Section newOrModifiedSectionBean) {
        this.newOrModifiedSectionBean = newOrModifiedSectionBean;
    }

    public List<User> getAssignableSectionManagers() {
        if (assignableSectionManagers == null) {
            if (filteredGroup == null) {
                this.assignableSectionManagers = userService.findAll();
            } else {
                this.assignableSectionManagers = userService.findAllByGroup(filteredGroup);
            }
        }
        if (assignedSectionManagers != null && !assignedSectionManagers.isEmpty()) {
            List<User> subtractionList = new ArrayList<User>(assignableSectionManagers);
            Iterator<UserMapper> iterator = assignedSectionManagers.iterator();
            while (iterator.hasNext()) {
                subtractionList.remove(iterator.next().getUser());
            }
            return subtractionList;
        }
        return assignableSectionManagers;
    }

    public List<Group> getGroups() {
        return groupService.findAll();
    }

    public List<User> getSelectedManagers() {
        return selectedManagers;
    }

    public String getUsernameForSelectComponent(String username) {
        for(User user : getAssignableSectionManagers()) {
            if (user.getUsername().equals(username)) {
                StringBuilder usernameValue = new StringBuilder(user.getFirstname() + " ");
                usernameValue.append(user.getLastname() + " (");
                usernameValue.append(user.getUsername() + ")");
                return usernameValue.toString();
            }
        }
        return null;
    }

    public void setSelectedManagers(List<User> selectedManagers) {
        this.selectedManagers = selectedManagers;
        if (assignedSectionManagers == null) {
            this.assignedSectionManagers = new ArrayList<UserMapper>();
        }
        for(User manager : selectedManagers) {
            assignedSectionManagers.add(new UserMapper(manager));
        }
    }

    public void selectLeaderManager(UserMapper leader) {
        for(UserMapper manager : assignedSectionManagers) {
            manager.setChecked(manager.equals(leader));
        }
    }

    public Group getFilteredGroup() {
        return filteredGroup;
    }

    public void setFilteredGroup(Group filteredGroup) {
        this.filteredGroup = filteredGroup;
        this.assignableSectionManagers = null;
    }

    public List<UserMapper> getAssignedSectionManagers() {
        return assignedSectionManagers;
    }

    public void setAssignedSectionManagers(List<UserMapper> assignedSectionManagers) {
        this.assignedSectionManagers = assignedSectionManagers;
    }

    public UIComponent getAssignedManagersUIComponent() {
        return assignedManagersUIComponent;
    }

    public void setAssignedManagersUIComponent(UIComponent assignedManagersUIComponent) {
        this.assignedManagersUIComponent = assignedManagersUIComponent;
    }

    public List<Section> getSections() {
        if (sections == null) {
            this.sections = sectionService.findAll();
        }
        return sections;
    }

    public void setSections(List<Section> sections) {
        this.sections = sections;
    }

    public List<Section> getFilteredSections() {
        return filteredSections;
    }

    public void setFilteredSections(List<Section> filteredSections) {
        this.filteredSections = filteredSections;
    }

    public String getManagerFullName(User manager) {
        return manager.getFirstname() + " " + manager.getLastname() + " (" + manager.getUsername() + ")";
    }

    public String getAssignedManagers(List<User> managers) {
        StringBuilder assignedManagers = new StringBuilder();
        for(User manager : managers) {
            assignedManagers.append(getManagerFullName(manager) + ", ");
        }
        return assignedManagers.toString().substring(0, assignedManagers.length()-2);
    }

    public Converter getGroupConverter() {
        return new Converter() {
            @Override
            public Object getAsObject(FacesContext context, UIComponent component, String value) {
                for(Group group : getGroups()) {
                    if (group.getGroupName().equals(value)) {
                        return group;
                    }
                }
                return null;
            }

            @Override
            public String getAsString(FacesContext context, UIComponent component, Object value) {
                return value != null ? ((Group)value).getGroupName() : null;
            }
        };
    }

    public Converter getSectionManagerConverter() {
        return new Converter() {
            @Override
            public Object getAsObject(FacesContext context, UIComponent component, String value) {
                for(User user : getAssignableSectionManagers()) {
                    if (user.getUsername().equals(value)) {
                        return user;
                    }
                }
                return null;
            }

            @Override
            public String getAsString(FacesContext context, UIComponent component, Object value) {
                return value.toString();
            }
        };
    }
}